#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include <iostream>
#include <mili/mili.h>
#include "prot-filer/fragments_filer.h"

using namespace std;
using namespace prot_filer;
using mili::insert_into;

class FragmentsImple : public Fragments
{
public:
    FragmentsImple(unsigned int _fragment_size) :
        fragment_size(_fragment_size)
    {}
    unsigned int get_fragment_size() const
    {
        return fragment_size;
    }
    AnglesData& operator[](unsigned int i)
    {
        return fragments[i];
    }
    void add(const AnglesData& data)
    {
        insert_into(fragments, data);
    }
private:
    unsigned int fragment_size;
    std::vector<AnglesData> fragments;
};

class FragmentFilerTest: public ::testing::Test
{
protected:
    virtual void SetUp()
    {
        AnglesData d1(3);
        d1.angles[0] = AngleIdPair(0, 0);
        d1.angles[1] = AngleIdPair(0, 0);
        AnglesData d2(3);
        d2.angles[0] = AngleIdPair(2, 0);
        d2.angles[1] = AngleIdPair(0, 2);
        fragments = new FragmentsImple(3);
        fragments->add(d1);
        fragments->add(d2);
    }

    FragmentsImple* fragments;
    void doTest(const vector<FragmentIds>& ids, const vector<AnglesData>& angles_data);
};

TEST_F(FragmentFilerTest, set1)
{
    const unsigned int nres = 7;

    //data
    AnglesMapping angles_mapping(nres);
    angles_mapping.set_mapping(-60, -40);
    angles_mapping.set_mapping(-60, 140);
    angles_mapping.set_mapping(-130, 140);
    angles_mapping.set_mapping(60, 30);

    vector<AnglesData> angles_data;
    vector<FragmentIds> fragment_ids;

    AnglesData data1(nres, &angles_mapping);
    data1.angles[0] = AngleIdPair(0, 0);
    data1.angles[1] = AngleIdPair(0, 0);
    data1.angles[2] = AngleIdPair(2, 0);
    data1.angles[3] = AngleIdPair(0, 2);
    data1.angles[4] = AngleIdPair(0, 0);
    data1.angles[5] = AngleIdPair(0, 0);
    insert_into(angles_data, data1);

    FragmentIds f1;
    insert_into(f1, 0);
    insert_into(f1, 1);
    insert_into(fragment_ids, f1);

    AnglesData data2(nres, &angles_mapping);
    data2.angles[0] = AngleIdPair(0, 0);
    data2.angles[1] = AngleIdPair(0, 0);
    data2.angles[2] = AngleIdPair(0, 0);
    data2.angles[3] = AngleIdPair(0, 0);
    data2.angles[4] = AngleIdPair(0, 0);
    data2.angles[5] = AngleIdPair(0, 0);
    insert_into(angles_data, data2);

    FragmentIds f2;
    insert_into(f2, 0);
    insert_into(f2, 0);
    insert_into(fragment_ids, f2);

    doTest(fragment_ids, angles_data);
}

TEST_F(FragmentFilerTest, set2)
{
    const unsigned int nres = 6;

    //data
    AnglesMapping angles_mapping(nres);
    angles_mapping.set_mapping(-60, -40);
    angles_mapping.set_mapping(-60, 140);
    angles_mapping.set_mapping(-130, 140);
    angles_mapping.set_mapping(60, 30);
    AnglesData data(nres, &angles_mapping);
    data.angles[0] = AngleIdPair(2, 0);
    data.angles[1] = AngleIdPair(0, 2);
    data.angles[2] = AngleIdPair(2, 0);
    data.angles[3] = AngleIdPair(0, 2);
    data.angles[4] = AngleIdPair(0, 0);
    vector<unsigned int> f1;
    insert_into(f1, 1);
    insert_into(f1, 1);

    vector<FragmentIds> ids;
    insert_into(ids, f1);
    vector<AnglesData> angles_data;
    insert_into(angles_data, data);

    doTest(ids, angles_data);
}

void FragmentFilerTest::doTest(const vector<FragmentIds>& ids, const vector<AnglesData>& angles_data)
{
    const string file = "test.xtc";
    FragmentsWriter w;
    w.open(file);
    for (unsigned int i = 0; i < ids.size(); ++i)
    {
        w.write(fragments->get_fragment_size(), ids[i], angles_data[i]);
    }
    w.close();

    FragmentsAnglesReaderImple r;
    r.open(fragments, file);
    const unsigned int nres = angles_data[0].nres;
    AnglesData p(nres);
    for (unsigned int i = 0; i < ids.size(); ++i)
    {
        r.read(p);
        for (unsigned int c = 0; c < nres - 1; ++c)
        {
            ASSERT_EQ(angles_data[i].angles[c].fi, p.angles[c].fi);
            ASSERT_EQ(angles_data[i].angles[c].si, p.angles[c].si);
        }
    }
    ASSERT_TRUE(r.read(p)); //eof
    r.close();
    remove(file.c_str());
}
